#include "led.h"
#include "preferencesUtil.h"
// NeoPixelBus<NeoRgbFeature, NeoTm1914Method> pixels(NUM_LEDS, DATA_PIN);
// Adafruit_NeoPixel pixels(NUM_LEDS, DATA_PIN, NEO_GRB + NEO_KHZ800);

HYled::~HYled()
{
    // log_d("析构函数执行...");
    // led_data = NULL;
    free(led_data);
    // pixels = 0;
    // oldPixels = 0;

    // rmt_obj_t *rmt_send = NULL;

    /*tm1914 C1、C2模式设置命令 0xFFFFFA_000000 */

    pinMode(config.gpio_num, INPUT);
    // ESP_ERROR_CHECK(gpio_set_direction(config.gpio_num, GPIO_MODE_OUTPUT));
}
HYled::HYled(led_chipLet chiplet)
{
    ledInit(chiplet);
}

HYled::HYled(led_chipLet chiplet, int ledpixels)
{
    ledInit(chiplet);
    setLedPixels(ledpixels);
}
void HYled::setLedPixels(int ledpixels)
{
    oldPixels = pixels;
    pixels = ledpixels;

    switch (chiplet)
    {
    case WS2811:

        break;
    case TM1914:
        pixels += 2; // 命令控制符空间
        // rgb总共24位

        break;
    default:
        break;
    }

    led_data = (rmt_data_t *)calloc(pixels * 24, sizeof(rmt_data_t));
    // memset(led_data, '\0', pixels * sizeof(rmt_data_t) * 24);

    // log_d("led_data:%d\n", sizeof(led_data)/sizeof(rmt_data_t));
    if (led_data == NULL)
    {
        // Serial.printf("rmt_data_t:%d\n",sizeof(rmt_data_t) );
        log_d("led_data:%d\n", sizeof(led_data) / sizeof(rmt_data_t));
        return;
    }
    // Serial.printf("rmt_data_t:%d\n",sizeof(rmt_data_t) );
    // Serial.printf("led_data:%d\n", sizeof(led_data));
}

void HYled::led_test_red()
{
    uint8_t light = 255;
    normalLED(light, 255, 0, 0);
}
void HYled::led_test_green()
{
    uint8_t light = 255;
    normalLED(light, 0, 255, 0);
}
void HYled::led_test_blue()
{
    uint8_t light = 255;
    normalLED(light, 0, 0, 255);
}
void HYled::led_point_test()
{
    color[0] = 255;
    color[1] = 255;
    color[2] = 255;
    int led, col;

    if (TM1914 == chiplet)
    {
        send_c1c2();
    }
    // Serial.println(chiplet);
    for (led = 0; led < pixels; led++)
    {
        for (col = 0; col < 3; col++)
        {
            int start = (led * 24) + (col * 8);
            if (led > 1 && TM1914 == chiplet)
            {

                led_writebyte_byt(color[col], start, 0, 8, 1, 4);
            }
            else if (chiplet == WS2811)
            {

                led_writebyte_byt(color[col], start, 1, 8, 0, 4);
            }
        }
        // ledInit(chiplet);
        // log_i("%d led light",led);
        ledShow();
        ledClear();
    }
}
void HYled::ledClear()
{
    ledClear(0);
    // memset(led_data, 0, pixels * sizeof(rmt_data_t) * 24);
}
void HYled::ledClear(uint32_t index)
{
    delay(200);
    int led, col;
    const int closeled[3] = {0, 0, 0};
    uint8_t light = 0;
    if (TM1914 == chiplet)
    {
        send_c1c2();
    }
    // Serial.println(chiplet);
    for (led = index; led < pixels; led++)
    {
        for (col = 0; col < 3; col++)
        {
            int start = (led * 24) + (col * 8);
            if (led > 1 && TM1914 == chiplet)
            {

                led_writebyte_byt(closeled[col], start, 0, 8, 1, 4);
            }
            else if (chiplet == WS2811)
            {

                led_writebyte_byt(closeled[col], start, 1, 8, 0, 4);
            }
        }
    }
    ledShow();
    // memset(led_data, 0, pixels * sizeof(rmt_data_t) * 24);
}
void HYled::led_color_change()
{
}
void HYled::setLedMode(led_mode ledmode, uint8_t &light, uint8_t red, uint8_t green, uint8_t blue)
{
    switch (ledmode)
    {
    case LEDNORMAL:
        normalLED(light, red, green, blue);
        ledShow();
        break;
    case RED:
        led_test_red();
        ledShow();
        break;
    case GREEN:
        led_test_green();
        ledShow();
        break;
    case BLUE:
        led_test_blue();
        ledShow();
        break;
    case POINT_TEST:
        led_point_test();
        break;
    case COLOR_CHANGE:
        led_color_change();
        break;
    }
}

void HYled::led_writebyte_byt(uint8_t byte, uint32_t start, uint32_t level0, uint32_t duration0, uint32_t level1, uint32_t duration1)
{
    const rmt_item32_t bit0 = {{{duration0, level0, duration1, level1}}}; // Logical 0
    const rmt_item32_t bit1 = {{{duration1, level0, duration0, level1}}}; // Logical 1
    for (int bit = 0; bit < 8; bit++)
    {
        int index = start + bit;
        // Serial.println(index);
        if ((byte & (1 << (7 - bit))))
        {
            (led_data + index)->val = bit0.val;
            // Serial.println(led_data[index].level0);
            //  Serial.println(led_data[index].level1);
        }
        else
        {
            (led_data + index)->val = bit1.val;
            // Serial.println("4");
        }
    }
}
void HYled::send_c1c2()
{

    for (int col = 0; col < 3; col++)
    {
        led_writebyte_byt(c1[col], (col * 8), 0, 8, 1, 4);
    }
    for (int col = 0; col < 3; col++)
    {
        led_writebyte_byt(c2[col], ((col * 8 + (24 * 1))), 0, 8, 1, 4);
    }
}
void HYled::led_all_writebyte_byt(uint8_t r, uint8_t g, uint8_t b)

{
    color[0] = r;
    color[1] = g;
    color[2] = b;

    int led = 0, col = 0;
    int i = 0;
    if (TM1914 == chiplet)
    {
        send_c1c2();
    }
    // Serial.println(chiplet);
    for (led = 0; led < pixels; led++)
    {
        for (col = 0; col < 3; col++)
        {
            int start = (led * 24) + (col * 8);
            if (led > 1 && TM1914 == chiplet)
            {

                led_writebyte_byt(color[col], start, 0, 8, 1, 4);
            }
            else if (WS2811 == chiplet)
            {

                led_writebyte_byt(color[col], start, 1, 8, 0, 4);
            }
        }

        // make the led travel in the pannel
        // if ((++led_index) >= NR_OF_LEDS)
        // {
        //     led_index = 0;
        // }
    }

    // make the led travel in the pannel
    // if ((++led_index) >= NR_OF_LEDS)
    // {
    //     led_index = 0;
    // }
}

/**
 * 普通的2811LED模式
 */

void HYled::normalLED(uint8_t &light, uint8_t red, uint8_t green, uint8_t blue)
{
    // pixels.clear();
    // pixels.SetBrightness(light);
    led_all_writebyte_byt(red, green, blue);
};

// rmt_data_t led_data[NR_OF_ALL_BITS];
void HYled::ws2811_init()
{

    // if (isConfig)
    // {
    //     destroyEnd();
    // }
    rmtTXConfig.carrier_freq_hz = 38000,
    rmtTXConfig.carrier_duty_percent = 33;
    rmtTXConfig.carrier_level = RMT_CARRIER_LEVEL_HIGH,
    rmtTXConfig.carrier_en = false;
    rmtTXConfig.loop_en = false;
    rmtTXConfig.idle_output_en = true;
    rmtTXConfig.idle_level = RMT_IDLE_LEVEL_LOW;

    config.gpio_num = GPIO_NUM_3;
    config.channel = RMT_CHANNEL_0;
    config.rmt_mode = RMT_MODE_TX;
    config.flags = 0;
    config.clk_div = 1;
    config.tx_config = rmtTXConfig;
    config.mem_block_num = RMT_MEM_64;
}
void HYled::tm1914_init()
{
    // if (isConfig)
    // {
    //     destroyEnd();
    // }

    // .rmt_mode = RMT_MODE_TX,
    // .channel = channel_id,
    // .gpio_num = gpio,
    // .clk_div = 1,
    // .mem_block_num = buffers,
    // .flags = 0,
    // .tx_config = {
    //     .carrier_level = RMT_CARRIER_LEVEL_HIGH,
    //     .idle_level = RMT_IDLE_LEVEL_LOW,
    //     .carrier_duty_percent = 50,
    //     .carrier_en = false,
    //     .loop_en = false,
    //     .idle_output_en = true,
    // }
    rmtTXConfig.carrier_freq_hz = 38000,
    rmtTXConfig.carrier_duty_percent = 33;
    rmtTXConfig.carrier_level = RMT_CARRIER_LEVEL_HIGH,
    rmtTXConfig.carrier_en = false;
    rmtTXConfig.loop_en = false;
    rmtTXConfig.idle_output_en = true;
    rmtTXConfig.idle_level = RMT_IDLE_LEVEL_HIGH;

    config.gpio_num = GPIO_NUM_3;
    config.channel = RMT_CHANNEL_0;
    config.rmt_mode = RMT_MODE_TX;
    config.flags = 0;
    config.clk_div = 1;
    config.tx_config = rmtTXConfig;
    config.mem_block_num = RMT_MEM_64;
}

// rmt_channel_t channel = ADAFRUIT_RMT_CHANNEL_MAX;
// for (size_t i = 0; i < ADAFRUIT_RMT_CHANNEL_MAX; i++)
// {
//     if (!rmt_reserved_channels[i])
//     {
//         rmt_reserved_channels[i] = true;
//         channel = (rmt_channel_t)i;
//         break;
//     }
// }
// if (channel == ADAFRUIT_RMT_CHANNEL_MAX)
// {
//     // Ran out of channels!
//     return;
// }
// Serial.printf("channel:%d \n", channel);
// config.channel = channel;

// Serial.printf("real tick set to: %fns\n", apb_tick);

void HYled::ledShow()
{

    pinMode(config.gpio_num, OUTPUT);
    digitalWrite(config.gpio_num, LOW); // 拉低电压
    delay(50);
    digitalWrite(config.gpio_num, HIGH);
    delay(50);
    rmt_config(&config);

    rmt_driver_install(config.channel, 0, ESP_INTR_FLAG_SHARED);

    rmt_set_source_clk(config.channel, RMT_BASECLK_APB);
    int apb_div = _LIMIT(100 / 12.5f, 256);
    float apb_tick = 12.5f * apb_div;

    ESP_ERROR_CHECK(rmt_set_clk_div(config.channel, apb_div & 0xFF));

    // bool isWaitTxDone = (WS2811 == chiplet ? true : false);
    // RMT_MUTEX_LOCK(config.channel);

    bool isWaitTxDone = true;

    rmt_tx_stop(config.channel);
    rmt_set_tx_loop_mode(config.channel, false);
    // ESP_ERROR_CHECK(rmt_tx_start(config.channel, true));
    rmt_write_items(config.channel, (const rmt_item32_t *)led_data, pixels * 24, isWaitTxDone);

    // rmt_wait_tx_done(config.channel, pdMS_TO_TICKS(100));

    // RMT_MUTEX_UNLOCK(config.channel);
    // destroyEnd();
    rmt_driver_uninstall(config.channel);
}

void HYled::ledInit(led_chipLet ledChipLet)
{

    // #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
    //     clock_prescale_set(clock_div_1);
    // #endif

    switch (ledChipLet)
    {
    case WS2811:
        chiplet = WS2811;
        /* code */
        ws2811_init();
        break;
    case TM1914:
        /* code */
        chiplet = TM1914;
        tm1914_init();
        break;
    default:
        chiplet = WS2811;
        /* code */
        ws2811_init();
        break;
    }
    // Serial.printf("chiplet:%d \n",chiplet);
    // prefs.setChipLet(chiplet);
}
static esp_err_t light_driver_hsv2rgb(uint16_t hue, uint8_t saturation, uint8_t value,
                                      uint8_t *red, uint8_t *green, uint8_t *blue)
{
    uint16_t hi = (hue / 60) % 6;
    uint16_t F = 100 * hue / 60 - 100 * hi;
    uint16_t P = value * (100 - saturation) / 100;
    uint16_t Q = value * (10000 - F * saturation) / 10000;
    uint16_t T = value * (10000 - saturation * (100 - F)) / 10000;

    switch (hi)
    {
    case 0:
        *red = value;
        *green = T;
        *blue = P;
        break;
    case 1:
        *red = Q;
        *green = value;
        *blue = P;
        break;
    case 2:
        *red = P;
        *green = value;
        *blue = T;
        break;
    case 3:
        *red = P;
        *green = Q;
        *blue = value;
        break;
    case 4:
        *red = T;
        *green = P;
        *blue = value;
        break;
    case 5:
        *red = value;
        *green = P;
        *blue = Q;
        break;
    default:
        return ESP_FAIL;
    }
    *red = *red * 255 / 100;
    *green = *green * 255 / 100;
    *blue = *blue * 255 / 100;
    return ESP_OK;
}

static void light_driver_rgb2hsv(uint16_t red, uint16_t green, uint16_t blue,
                                 uint16_t *h, uint8_t *s, uint8_t *v)
{
    double hue, saturation, value;
    double m_max = MAX(red, MAX(green, blue));
    double m_min = MIN(red, MIN(green, blue));
    double m_delta = m_max - m_min;

    value = m_max / 255.0;
    if (m_delta == 0)
    {
        hue = 0;
        saturation = 0;
    }
    else
    {
        saturation = m_delta / m_max;
        if (red == m_max)
        {
            hue = (green - blue) / m_delta;
        }
        else if (green == m_max)
        {
            hue = 2 + (blue - red) / m_delta;
        }
        else
        {
            hue = 4 + (red - green) / m_delta;
        }
        hue = hue * 60;
        if (hue < 0)
        {
            hue = hue + 360;
        }
    }
    *h = (int)(hue + 0.5);
    *s = (int)(saturation * 100 + 0.5);
    *v = (int)(value * 100 + 0.5);
}